#pragma once
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>

namespace ns_threadPool
{
    class threadPool
    {
    public:
        threadPool(size_t threads) : stop(false)
        {
            for (size_t i = 0; i < threads; ++i)
            {
                // 使用lambda表达式初始化thread对象
                workers.emplace_back([this]     
                {
                    //  循环从队列中获取task
                    while(true) 
                    {
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lock(this->queue_mutex);   // 出作用域自动解锁
                            // 等待条件变量，直到有任务可执行或线程池停止
                            condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
                            //  重复进行条件检测，避免伪唤醒
                            if(this->stop && this->tasks.empty())
                                return;

                            task = std::move(this->tasks.front());
                            this->tasks.pop();
                        }
                        try 
                        {
                            task();
                        } catch (const std::exception& e) 
                        {
                            std::cerr << "Task threw an exception: " << e.what() << std::endl;
                        } catch (...) {
                            std::cerr << "Task threw an unknown exception." << std::endl;
                        }
                    } 
                });
            }
        }

        //  本质上，将一个函数+参数打包成task对象，放入queue队列中，交由thread进行读取执行
        template <class F, class... Args>
        auto enqueue(F &&f, Args &&...args)-> std::future<typename std::result_of<F(Args...)>::type>    // 类型萃取
        {
            using return_type = typename std::result_of<F(Args...)>::type;

            auto task = std::make_shared<std::packaged_task<return_type()>>(
                std::bind(std::forward<F>(f), std::forward<Args>(args)...));

            std::future<return_type> res = task->get_future();
            {
                std::unique_lock<std::mutex> lock(queue_mutex);
                if (stop)
                    throw std::runtime_error("enqueue on stopped threadPool");
                tasks.emplace([task]()
                              { (*task)(); });
            }
            condition.notify_one();
            return res;
        }

        ~threadPool()
        {
            {
                //  加锁，避免竞争引发二义性
                std::unique_lock<std::mutex> lock(queue_mutex);
                stop = true;
            }
            //  通知所有在cond等待的线程，它们根据自身task执行情况判断是否退出
            condition.notify_all();
            for (std::thread &worker : workers)
                worker.join();  //  遍历workers，由主线程等待所有子线程执行，保证任务全部完成
        }

    private:
        std::vector<std::thread> workers;
        std::queue<std::function<void()>> tasks;
        std::mutex queue_mutex;
        std::condition_variable condition;
        bool stop;
    };
}